<?
открыть config.php и найти:

	'bb_login_err'  => array('filecache', array()),
	
после вставить:

	'buf_where'     => array('db_sqlite', array('columns' => 'user_ip INT, username TEXT, user_id INT, user_rank INT, user_opt INT, forum_id INT, id INT, title TEXT, type TEXT, time INT')),

найти конец файла
перед вставить:

$bb_cfg['where_user'] = true;


открыть functions.php и найти:

	if (!in_array($user_id, array('', GUEST_UID, BOT_UID)) && $username)
	{
		$profile = '<a href="'. make_url(PROFILE_URL . $user_id) .'">'. $profile .'</a>';
	}
заменить на

	if (!in_array($user_id, array('', GUEST_UID, BOT_UID)) && $username)
	{
        $profile = '<span class="nowrap"><a href="'. make_url(PROFILE_URL . $user_id) .'">'. $profile .'</a> <span onclick="user_popup('. $user_id .', \''. $username .'\');" title="Просмотр профиля" class="popup clickable"><span class="pad_6"></span></span></span>';
	}

в конец добавить:

function where_user($data)
{
    global $bb_cfg, $lang, $userdata;

    if(!$bb_cfg['where_user']) return;

    $where_time = (TIMENOW - 300);
    $buf = CACHE('buf_where')->fetch_row("
		SELECT time FROM buf_where
		WHERE type       = '{$data['type']}'
			AND forum_id = {$data['forum_id']}
		    AND user_ip  = '". USER_IP ."'
			AND time     > $where_time
		    AND id       = {$data['id']}
		ORDER BY time DESC");
    $insert = true;
    if($buf) $insert = false;

    $sql['user_ip']    = USER_IP;
    $sql['username']   = $userdata['username'];

    /*
    if(IS_GUEST)
    {
        $user_browser = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'not browser';

        foreach ($bb_cfg['bots'] as $bot => $name)
        {
            if(strstr($user_browser, $bot)) $sql['username'] = $name;
        }
    }
    */

    $sql['user_id']    = $userdata['user_id'];
    $sql['user_rank']  = $userdata['user_rank'];
    $sql['user_opt']   = $userdata['user_opt'];
    $sql['time']       = TIMENOW;
    $sql['type']       = @$data['type'];
    $sql['forum_id']   = @$data['forum_id'];
    $sql['id']         = @$data['id'];
    $sql['title']      = @htmlCHR($data['title']);

    $sql_insert = DB()->build_array('INSERT', $sql);
    if($insert) CACHE('buf_where')->query("INSERT INTO buf_where $sql_insert");
}

function where_user_url($data, $obrezka = true)
{
    global $lang, $bb_cfg;

    if(!$bb_cfg['where_user']) return '---';

    $title = html_ent_decode($data['title']);
    $old_title = $title;
    if($obrezka && $data['type'] != 'profile' && $title) $title = str_short($title, 60);

    switch($data['type'])
    {
        case 'index':
            return 'Просмотр главной страницы <a href="'. make_url('index.php') .'" target="_blank">'. $title .'</a>';
            break;

        case 'topic':
        case 'post':
            $topic = ($data['type'] == 'post') ? '<a href="'. (POST_URL . $data['id'] .'#'. $data['id']) .'" target="_blank">'. $title .'</a>' : '<a href="'. (TOPIC_URL . $data['id']) .'" target="_blank">'. $title .'</a>';
            return 'Просмотр темы '. $topic;
            break;

        case 'forum':
            $forum = '<a href="'. (FORUM_URL . $data['id']) .'" target="_blank">'. $title .'</a>';
            return 'Просмотр форума '. $forum;
            break;

        case 'orders':
            return 'Просмотр <a href="/orders.php" target="_blank">Стола заказов</a>';
            break;

        case 'profile':
            return 'Просмотр профиля '. $title;
            break;

        case 'search':
            return 'Использует поиск по форуму';
            break;

        case 'tracker':
            return 'Использует поиск по трекеру';
            break;

        case 'nya':
            return 'Смотрит цитаты с няша';
            break;

        case 'torrent':
            return "Скачал торрент в <a href='$title'>этой</a> раздачи";
            break;

        case 'online':
            return "Смотрит <a href='viewonline.php'>Кто онлайн</a>";
            break;

        case 'chat':
            return "<a href='chat.php'>Просматривает чат</a>";
            break;
    }
}


открыть index.php и найти:

// Init userdata
$user->session_start();

после вставить:

if(!IS_GUEST) where_user(array('id' => 0, 'forum_id' => 0, 'type' => 'index', 'title' => $bb_cfg['sitename']));

открыть viewtopic.php и найти 

$topic_has_poll = ($t_data['topic_vote'] && !IS_GUEST);
$poll_time_expired = ($t_data['topic_time'] < TIMENOW - $bb_cfg['poll_max_days']*86400);
$can_manage_poll = ($t_data['topic_poster'] == $userdata['user_id'] || $is_auth['auth_mod']);
$can_add_poll = ($can_manage_poll && !$topic_has_poll && !$poll_time_expired && !$start);

после вставить

if(!IS_GUEST)
{
	$where_type = ($post_id) ? 'post' : 'topic';
	$where_id   = ($post_id) ? $post_id : $t_data['topic_id'];
	where_user(array('id' => $where_id, 'forum_id' => $t_data['forum_id'], 'type' => $where_type, 'title' => $t_data['topic_title']));
}

if($bb_cfg['where_user'] && !IS_GUEST)
{
	$where_time = (TIMENOW - 300);
	$user_list = array();
	$sql = CACHE('buf_where')->fetch_rowset("
		SELECT * FROM buf_where
		WHERE (type = 'post' OR type = 'topic' OR type = 'posting')
			AND forum_id = {$t_data['forum_id']}
			AND id = {$where_id}
			AND time     > $where_time
		GROUP BY time
		ORDER BY time DESC");
	$guest = $users = $hide_users = 0;
	foreach($sql as $row)
	{
		$profile = str_replace('title="', 'data="', profile_url($row));
		$time = delta_time($row['time']);

		if(bf($row['user_opt'], 'user_opt', 'user_viewonline'))
		{
			$hide_users++;
			if(IS_ADMIN)
			{
				$user_list[] = '<span title="'. $time .'" style="border-bottom: 1px dashed #000; padding-bottom: 2px;">'. $profile .'</span>';
			}
		}
		else if($row['user_id'] == GUEST_UID)
		{
			$guest++;
			$user_list[] = '<span title="'. $time .'">'. $profile .'</span>';
		}
		else
		{
			$users++;
			$user_list[] = '<span title="'. $time .'">'. $profile .'</span>';
		}
	}

	$text = ($users + $hide_users) ." человек читают эту тему: $users пользователей, $hide_users скрытых пользователей, $guest гостей";
	$list = join(', ', $user_list);

	$template->assign_vars(array(
		'USER_TEXT' => $text,
		'USER_LIST' => $list,
	));
}

открыть viewforum.php и найти

if($forums['forum'][$forum_id]['allow_porno_topic'] && bf($userdata['user_opt'], 'user_opt', 'user_porn_forums')) bb_die($lang['ERROR_PORNO_FORUM']);

после вставить

if(!IS_GUEST) where_user(array('id' => $forum_id, 'forum_id' => $forum_id, 'type' => 'forum', 'title' => $forums['forum_name_html'][$forum_id]));

if($bb_cfg['where_user'] && !IS_GUEST)
{
	$where_time = (TIMENOW - 300);
	$user_list = array();
	$sql = CACHE('buf_where')->fetch_rowset("
		SELECT * FROM buf_where
		WHERE type = 'forum'
			AND forum_id = $forum_id
			AND id = {$forum_id}
			AND time     > $where_time
		ORDER BY time DESC");
	$guest = $users = $hide_users = 0;
	foreach($sql as $row)
	{
		$profile = str_replace('title="', 'data="', profile_url($row));
		$time = delta_time($row['time']);

		if(bf($row['user_opt'], 'user_opt', 'user_viewonline'))
		{
			$hide_users++;
			if(IS_ADMIN)
			{
				$user_list[] = '<span title="'. $time .'" style="border-bottom: 1px dashed #000; padding-bottom: 2px;">'. $profile .'</span>';
			}
		}
		else if($row['user_id'] == GUEST_UID)
		{
			$guest++;
			$user_list[] = '<span title="'. $time .'">'. $profile .'</span>';
		}
		else
		{
			$users++;
			$user_list[] = '<span title="'. $time .'">'. $profile .'</span>';
		}
	}

	$text = ($users + $hide_users) ." человек читают этот форум: $users пользователей, $hide_users скрытых пользователей, $guest гостей";
	$list = join(', ', $user_list);

	$template->assign_vars(array(
		'USER_TEXT' => $text,
		'USER_LIST' => $list,
	));
}


открыть index_data.php и найти:

case 'change_tz':
		$tz = (int) $this->request['tz'];
		if ($tz < -12) $tz = -12;
		if ($tz > 13) $tz = 13;
		if ($tz != $bb_cfg['board_timezone'])
		{
			// Set current user timezone
			DB()->query("UPDATE ". BB_USERS ." SET user_timezone = $tz WHERE user_id = ". $userdata['user_id'] ." LIMIT 1");
			$bb_cfg['board_timezone'] = $tz;
			cache_rm_user_sessions ($userdata['user_id']);
		}
	break;
	
после вставить:

	case 'user_popup':
        $user_id = (int) $this->request['user_id'];
        $data = get_userdata($user_id);
        if ($data['user_id'] == GUEST_UID || $data['user_id'] == BOT_UID || !$data)
        {
            $this->ajax_die('Пользователь не найден');
        }

        $where_time = (TIMENOW - 300);
        $where = CACHE('buf_where')->fetch_row("
			SELECT * FROM buf_where
			WHERE user_id  = '". $data['user_id'] ."'
				AND time  > $where_time
			ORDER BY time DESC");

        $datastore->enqueue(array(
            'ranks',
        ));

        $ranks = $datastore->get('ranks');
        $rank_title = $lang['USER'];
        $rank_image = $rank_style = '';

        if ($user_rank = $data['user_rank'] AND isset($ranks[$user_rank]))
        {
            $rank_image = $ranks[$user_rank]['rank_image'];
            $rank_title = $ranks[$user_rank]['rank_title'];
            $rank_style = $ranks[$user_rank]['rank_style'];
        }

        if(bf($data['user_opt'], 'user_opt', 'user_viewonline') && !IS_ADMIN)
        {
            $lastvisit = '<div class="pad_2"><b>Последняя активность</b>: скрыто</div>';
        }
        else
        {
            if($where >= (TIMENOW - 300))
            {
                $text = where_user_url($where);

                $lastvisit = '<div class="pad_2"><b>Последняя активность</b>: '. bb_date($data['user_session_time']) .'</div>';
                $lastvisit .= '<div class="pad_2"><b>Сейчас</b>: '. $text .'</div>';
            }
            else
            {
                $lastvisit = '<div class="pad_2"><b>Сейчас</b>: Offline</div>';
            }
        }

        $avatar = get_avatar($data['user_id'], $data['avatar_ext_id'], !bf($data['user_opt'], 'user_opt', 'dis_avatar'));

        $html .= '<div class="pad_4">
			'. str_replace('<img', '<img width="100" align="right"', $avatar) .'
			<div class="pad_2"><b>Звание</b>: <span class="'. $rank_style .'">'. $rank_title .'</span></div>
			<div class="pad_2"><b>Зарегистрирован</b>: '. bb_date($data['user_regdate']) .'</div>
		    <div class="pad_2"><b>Всего сообщений</b>: '. $data['user_posts'] .'</div>
				'. $lastvisit .'
			<div class="clear pad_4"></div>
			<div class="hr pad_2">
				<a href="'. PROFILE_URL . $user_id .'">[профиль]</a>
			    <a href="'. PM_URL .'?mode=post&amp;u='. $user_id .'">[Отправить ЛС]</a>
			</div>
		</div>';
        break;


открыть viewtopic.tpl и найти:

<!-- IF QUICK_REPLY -->

перед вставить:

<!-- IF $bb_cfg['where_user'] -->
<div class="category row1 border bw_TRBL mrg_8 pad_4">
{USER_TEXT}
<br /><br />
{USER_LIST}
</div>
<!-- ENDIF -->

открыть viewforum.tpl и найти:

<!--bottom_info-->
<div class="bottom_info">

перед вставить:

<!-- IF $bb_cfg['where_user'] -->
<div class="category row1 border bw_TRBL mrg_8 pad_4">
	{USER_TEXT}
	<br /><br />
	{USER_LIST}
</div>
<!-- ENDIF -->

открыть page_header.tpl и найти:

<!--=================-->
<!-- ELSEIF IN_ADMIN -->
<!--=================-->

<!--======-->
<!-- ELSE -->
<!--======-->

после вставить:

<script type="text/javascript" src="{SITE_URL}styles/js/ui/jquery-ui.js?v={$bb_cfg['js_ver']}"></script>
<link rel="stylesheet" href="{SITE_URL}styles/js/ui/jquery-ui.css?v={$bb_cfg['css_ver']}" type="text/css">
<script type="text/javascript">
    function user_popup(user_id, name) {
        //$("#user_popup").dialog( "destroy" );
        $("#user_popup").show().attr({title: 'Пользователь: '+name}).html('<i class="loading-1">Загружается…</i>').dialog({
            height: 210,
            width: 400,
        });
        ajax.exec({
            action  : 'index_data',
            mode    : 'user_popup',
            user_id : user_id,
        });
        ajax.callback.index_data = function(data) {
            $('#'+data.mode).html(data.html);
        };
    }
</script>

<div id="user_popup" class="hidden med"></div>

открыть main.css и найти:

.vTop      { vertical-align: top !important; }

после вставить:

.popup {
    background: url(../images/popup.png) no-repeat;
    width: 8px;
    height: 8px;
}